<template>
  <div class="upload-file">
    <div class="upload-buttons">
      <!-- 单个文件上传按钮（保留，兼容多场景） -->
      <el-upload
        multiple
        :action="uploadFileUrl"
        :before-upload="handleBeforeUpload"
        :file-list="fileList"
        :data="data"
        :limit="100"
        :on-error="handleUploadError"
        :on-exceed="handleExceed"
        :on-success="handleUploadSuccess"
        :show-file-list="false"
        :headers="headers"
        class="upload-file-uploader"
        ref="fileUpload"
        v-if="!disabled"
      >
        <!-- <el-button size="mini" type="primary">选取文件</el-button> -->
      </el-upload>

      <!-- 文件夹上传按钮 -->
      <!-- <el-button
        size="mini"
        type="success"
        class="folder-upload-btn"
        @click="selectFolder"
        v-if="!disabled"
      >
        <i class="el-icon-folder-opened" v-if="!isUploading"></i>
        <i class="el-icon-loading el-icon--right" v-if="isUploading"></i>
        {{ isUploading ? '上传中...' : '选取文件夹' }}
      </el-button> -->

      <!-- 上传提示 -->
      <div class="el-upload__tip" slot="tip" v-if="showTip">
        支持{{ fileType.join("/") }}格式，
        <template v-if="fileSize">单文件≤<b style="color: #f56c6c">{{ fileSize }}MB</b></template>
        <template v-if="fileType.includes('zip')">，压缩包≤50MB</template>
      </div>
    </div>

    <!-- 文件列表（父组件可通过ref获取） -->
    <transition-group ref="uploadFileList" class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
        <el-link :href="file.url" :underline="false" target="_blank" v-if="file.url">
          <span v-if="file.isDirectory" class="el-icon-folder"> {{ file.relativePath }} </span>
          <span v-else class="el-icon-document"> {{ file.relativePath || getFileName(file.name) }} </span>
        </el-link>
        <div class="ele-upload-list__item-content-action">
          <el-link :underline="false" @click="handleDelete(index)" type="danger" v-if="!disabled && !isUploading">删除</el-link>
        </div>
      </li>
    </transition-group>

    <!-- 文件夹上传隐藏Input（内部使用） -->
    <input
      type="file"
      ref="folderInput"
      style="display: none"
      webkitdirectory
      directory
      @change="handleFolderSelect"
      :accept="acceptTypes"
    >
  </div>
</template>

<script>
import { getToken } from "@/utils/auth";
import Sortable from "sortablejs";

export default {
  name: "FileUpload",
  props: {
    value: [String, Object, Array], // 父组件传入的已选文件
    action: { type: String, default: "/file/upload" }, // 上传接口
    data: { type: Object }, // 上传额外参数
    limit: { type: Number, default: 100 }, // 文件数量限制（文件夹上传需更大）
    fileSize: { type: Number, default: 20 }, // 普通文件大小限制（MB）
    fileType: {
      type: Array,
      default: () => ["jpg", "jpeg", "png", "zip", "rar", "doc", "docx","pdf"]
    }, // 支持的文件类型
    isShowTip: { type: Boolean, default: true }, // 是否显示提示
    disabled: { type: Boolean, default: false }, // 是否禁用
    drag: { type: Boolean, default: true } // 是否支持拖拽排序
  },
  data() {
    return {
      uploadFileUrl: process.env.VUE_APP_BASE_API + this.action, // 完整上传地址
      headers: { Authorization: "Bearer " + getToken() }, // 请求头（带token）
      fileList: [], // 已选/已上传文件列表
      folderInput: null, // 文件夹选择Input引用
      isUploading: false, // 是否正在上传
      uploadedCount: 0, // 上传成功数量
      failedCount: 0, // 上传失败数量
      uploadQueue: [], // 上传队列
      selectedFolderInfo: null, // 选中的文件夹信息（名称、文件数等）
      uploadAborted: false // 是否取消上传
    };
  },
  computed: {
    showTip() {
      return this.isShowTip && (this.fileType || this.fileSize);
    },
    // 生成accept属性（用于过滤文件选择）
    acceptTypes() {
      const typeMap = {
        jpg: "image/jpeg",
        jpeg: "image/jpeg",
        png: "image/png",
        pdf: "application/pdf",
        zip: "application/zip",
        rar: "application/x-rar-compressed",
        doc: "application/msword",
        docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
      };
      return this.fileType.map(type => typeMap[type] || "").filter(Boolean).join(",");
    }
  },
  mounted() {
    this.folderInput = this.$refs.folderInput;
    // 初始化拖拽排序
    if (this.drag && !this.disabled) {
      this.$nextTick(() => {
        const element = this.$refs.uploadFileList?.$el || this.$refs.uploadFileList;
        if (element) {
          Sortable.create(element, {
            ghostClass: "file-upload-darg",
            onEnd: (evt) => {
              const movedItem = this.fileList.splice(evt.oldIndex, 1)[0];
              this.fileList.splice(evt.newIndex, 0, movedItem);
              this.$emit("input", this.listToString(this.fileList));
            }
          });
        }
      });
    }
    // 通知父组件：组件初始化完成
    this.$emit("initialized", true);
  },
  watch: {
    // 监听父组件传入的value，同步到fileList
    value: {
      handler(val) {
        if (val) {
          const list = Array.isArray(val) ? val : val.split(",");
          this.fileList = list.map((item, idx) => {
            const file = typeof item === "string" ? { name: item, url: item } : item;
            return { ...file, uid: file.uid || Date.now() + idx, relativePath: file.relativePath || file.name };
          });
        } else {
          this.fileList = [];
        }
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    // 触发文件夹选择
    selectFolder() {
      if (this.isUploading) return;
      if (!this.folderInput) {
        this.$emit("upload-error", new Error("文件夹选择器未初始化"), null);
        return;
      }
      if (typeof this.folderInput.webkitdirectory === "undefined") {
        this.$emit("upload-error", new Error("请使用Chrome/Edge等现代浏览器"), null);
        return;
      }
      // 重置上传状态
      this.resetUploadState();
      this.folderInput.value = "";
      this.folderInput.click();
    },

    // 处理文件夹选择
    handleFolderSelect(e) {
      const files = e.target.files;
      if (!files || files.length === 0) {
        this.$emit("upload-error", new Error("未选择任何文件"), null);
        return;
      }
      // 解析文件夹信息
      const firstFile = files[0];
      const folderName = firstFile.webkitRelativePath.split("/")[0];
      const allFiles = Array.from(files);

      // 过滤有效文件（验证类型+大小）
      const validFiles = allFiles.filter(file => this.validateFile(file));
      const invalidCount = allFiles.length - validFiles.length;

      // 存储文件夹信息
      this.selectedFolderInfo = {
        name: folderName,
        validFileCount: validFiles.length,
        totalFileCount: allFiles.length,
        invalidCount,
        files: validFiles.map(file => ({
          rawFile: file,
          relativePath: file.webkitRelativePath,
          name: file.name,
          size: file.size,
          ext: file.name.split(".").pop().toLowerCase(),
          uid: Date.now() + Math.random()
        }))
      };
      // 通知父组件：文件夹已选择
      this.$emit("folder-selected", this.selectedFolderInfo);

      if (validFiles.length === 0) {
        this.$emit("upload-error", new Error(`无有效文件！支持${this.fileType.join("/")}，图片≤12MB，压缩包≤50MB`), null);
        return;
      }
      // 检查数量限制
      if (this.fileList.length + validFiles.length > this.limit) {
        this.$emit("upload-error", new Error(`上传文件数量不能超过${this.limit}个`), null);
        return;
      }
      // 初始化上传队列并开始上传
      this.uploadQueue = [...this.selectedFolderInfo.files];
      this.startBatchUpload();
    },

    // 开始批量上传
    startBatchUpload() {
      if (this.isUploading || this.uploadQueue.length === 0) return;
      // 通知父组件：上传开始
      this.isUploading = true;
      this.uploadAborted = false;
      this.uploadedCount = 0;
      this.failedCount = 0;
      this.$emit("upload-start", this.uploadQueue.length);

      // 逐个上传文件
      this.uploadNextFile();
    },

    // 上传队列中的下一个文件
    async uploadNextFile() {
      if (this.uploadAborted || !this.isUploading || this.uploadQueue.length === 0) {
        this.finishUpload();
        return;
      }
      // 获取当前文件
      const fileItem = this.uploadQueue.shift();
      try {
        // 调用上传接口（FormData携带额外参数+相对路径）
        const formData = new FormData();
        formData.append("file", fileItem.rawFile);
        // 追加父组件传入的额外参数
        if (this.data) {
          Object.keys(this.data).forEach(key => formData.append(key, this.data[key]));
        }
        // 追加文件夹路径信息（用于服务端保持结构）
        formData.append("relativePath", fileItem.relativePath);
        formData.append("folderName", this.selectedFolderInfo.name);

        // 发送上传请求
        const response = await this.requestUpload(formData, fileItem);
        if (response.code === 200) {
          // 上传成功：添加到文件列表
          const uploadedFile = {
            ...fileItem,
            url: response.data.url,
            status: "success"
          };
          this.fileList.push(uploadedFile);
          this.uploadedCount++;
          // 通知父组件：单个文件成功
          this.$emit("upload-success", uploadedFile, response);
          // 更新进度
          this.emitProgress();
        } else {
          throw new Error(response.msg || "上传失败");
        }
      } catch (error) {
        this.failedCount++;
        // 通知父组件：单个文件失败
        this.$emit("upload-error", error, fileItem);
        // 更新进度
        this.emitProgress();
      }
      // 递归上传下一个
      if (!this.uploadAborted) {
        setTimeout(() => this.uploadNextFile(), 300); // 间隔300ms避免请求密集
      } else {
        this.finishUpload();
      }
    },

    // 发送上传请求（封装axios）
    requestUpload(formData, fileItem) {
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open("POST", this.uploadFileUrl, true);
        // 设置请求头（排除Content-Type，由浏览器自动处理multipart/form-data）
        Object.keys(this.headers).forEach(key => {
          if (key.toLowerCase() !== "content-type") {
            xhr.setRequestHeader(key, this.headers[key]);
          }
        });
        // 进度监听
        xhr.upload.addEventListener("progress", (e) => {
          if (e.lengthComputable) {
            const progress = Math.round((e.loaded / e.total) * 100);
            this.$emit("file-progress", { file: fileItem, progress });
          }
        });
        // 响应处理
        xhr.onload = () => {
          if (xhr.status >= 200 && xhr.status < 300) {
            try {
              const res = JSON.parse(xhr.responseText);
              resolve(res);
            } catch (err) {
              reject(new Error("响应解析失败"));
            }
          } else {
            reject(new Error(`HTTP错误：${xhr.status}`));
          }
        };
        // 错误处理
        xhr.onerror = () => reject(new Error("网络错误"));
        xhr.send(formData);
      });
    },

    // 验证文件（类型+大小）
    validateFile(file) {
      const fileExt = file.name.split(".").pop().toLowerCase();
      const fileSizeMB = file.size / 1024 / 1024;
      // 类型验证
      if (!this.fileType.includes(fileExt)) return false;
      // 大小验证（压缩包单独限制50MB）
      const sizeLimit = fileExt === "zip" || fileExt === "rar" ? 50 : this.fileSize;
      return fileSizeMB <= sizeLimit;
    },

    // 单个文件上传前验证（兼容el-upload的单个文件上传）
    handleBeforeUpload(file) {
      if (!this.validateFile(file)) return false;
      this.$emit("upload-start", 1);
      this.isUploading = true;
      return true;
    },

    // el-upload单个文件上传成功
    handleUploadSuccess(res, file) {
      if (res.code === 200) {
        const uploadedFile = {
          ...file,
          url: res.data.url,
          relativePath: file.name,
          uid: file.uid || Date.now()
        };
        this.fileList.push(uploadedFile);
        this.uploadedCount++;
        this.$emit("upload-success", uploadedFile, res);
      } else {
        this.failedCount++;
        this.$emit("upload-error", new Error(res.msg), file);
      }
      this.finishUpload();
    },

    // el-upload单个文件上传失败
    handleUploadError(err, file) {
      this.failedCount++;
      this.$emit("upload-error", err, file);
      this.finishUpload();
    },

    // 文件数量超出限制
    handleExceed() {
      this.$emit("upload-error", new Error(`上传文件数量不能超过${this.limit}个`), null);
    },

    // 完成所有上传
    finishUpload() {
      this.isUploading = false;
      // 通知父组件：上传完成
      this.$emit("upload-finish", {
        uploadedCount: this.uploadedCount,
        failedCount: this.failedCount,
        totalCount: this.uploadedCount + this.failedCount,
        folderInfo: this.selectedFolderInfo
      });
    },

    // 取消上传
    cancelUpload() {
      this.uploadAborted = true;
      this.isUploading = false;
      this.uploadQueue = [];
      this.$emit("upload-cancel", { uploadedCount: this.uploadedCount, failedCount: this.failedCount });
    },

    // 重置上传状态
    resetUploadState() {
      this.isUploading = false;
      this.uploadedCount = 0;
      this.failedCount = 0;
      this.uploadQueue = [];
      this.selectedFolderInfo = null;
      this.uploadAborted = false;
      this.$emit("upload-reset");
    },

    // 删除文件
    handleDelete(index) {
      const deletedFile = this.fileList.splice(index, 1)[0];
      this.$emit("file-delete", deletedFile);
      this.$emit("input", this.listToString(this.fileList));
    },

    // 清空所有文件
    clearFiles() {
      this.fileList = [];
      this.$emit("input", "");
    },

    // 文件列表转字符串（用于v-model）
    listToString(list, separator = ",") {
      return list.length ? list.map(item => item.url).join(separator) : "";
    },

    // 获取文件名（去掉路径）
    getFileName(name) {
      return name.lastIndexOf("/") > -1 ? name.slice(name.lastIndexOf("/") + 1) : name;
    },

    // 发射进度更新（总进度）
    emitProgress() {
      const total = this.selectedFolderInfo ? this.selectedFolderInfo.validFileCount : 1;
      const progress = Math.round(((this.uploadedCount + this.failedCount) / total) * 100);
      this.$emit("upload-progress", progress, {
        uploaded: this.uploadedCount,
        failed: this.failedCount,
        total
      });
    }
  }
};
</script>

<style scoped lang="scss">
.upload-buttons {
  display: flex;
  gap: 10px;
  margin-bottom: 10px;
  align-items: center;
}
.folder-upload-btn {
  margin-bottom: 5px;
}
.upload-file-uploader {
  margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
  border: 1px solid #e4e7ed;
  line-height: 2;
  margin-bottom: 8px;
  padding: 8px 12px;
  border-radius: 4px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.ele-upload-list__item-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}
.ele-upload-list__item-content-action .el-link {
  margin-left: 16px;
  color: #f56c6c;
}
.el-icon-folder {
  color: #409eff;
  margin-right: 6px;
}
.el-icon-document {
  margin-right: 6px;
  color: #67c23a;
}
.el-upload__tip {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
}
.file-upload-darg {
  opacity: 0.5;
  background: #c8ebfb;
}
</style>
